{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Idiomatic Python - miscellaneous part 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comprehensions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "original_data = (1, 2, 3, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# list\n",
    "square_roots_list = []\n",
    "for val in original_data:\n",
    "    square_root = val**(1/2) \n",
    "    square_roots_list.append(square_root)\n",
    "print(square_roots_list)\n",
    "\n",
    "# set\n",
    "square_roots_set = set()\n",
    "for val in original_data:\n",
    "    square_root = val**(1/2) \n",
    "    square_roots_set.add(square_root)\n",
    "print(square_roots_set)\n",
    "\n",
    "# dict\n",
    "square_roots_dict = {}\n",
    "for val in original_data:\n",
    "    square_root = val**(1/2) \n",
    "    square_roots_dict[val] = square_root\n",
    "print(square_roots_dict) \n",
    "\n",
    "# dict with a condition\n",
    "integer_square_roots_dict = {}\n",
    "for val in original_data:\n",
    "    square_root = val**(1/2)\n",
    "    if square_root.is_integer():\n",
    "        integer_square_roots_dict[val] = square_root\n",
    "print(integer_square_roots_dict) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note: in case you're using 2.X version of Python for some reason, the result of `1/2` is `0` instead of `0.5`. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>Use comprehensions!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "square_roots_list = [val**(1/2) for val in original_data]\n",
    "print(square_roots_list)\n",
    "\n",
    "square_roots_set = {val**(1/2) for val in original_data}\n",
    "print(square_roots_set)\n",
    "\n",
    "square_roots_dict = {val: val**(1/2) for val in original_data}\n",
    "print(square_roots_dict)\n",
    "\n",
    "integer_square_roots_dict = {\n",
    "    val: val**(1/2)\n",
    "    for val in original_data if (val**(1/2)).is_integer()\n",
    "}\n",
    "print(integer_square_roots_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using `in` for checking presence of an element in a collection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "name = 'John Doe'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do it like this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if name == 'John' or name == 'Doe' or name == 'John Doe':\n",
    "    print('This seems to be our guy')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>Do it like this!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if name in ('John', 'Doe', 'John Doe'):\n",
    "    print('This seems to be our guy')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Chained comparisons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a, b, c, d = 1, 2, 3, 4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do it like this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if b > a and c > b and d > c:\n",
    "    print('from lowest to highest: a, b, c, d')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>Do it like this!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if a < b < c < d:\n",
    "    print('from lowest to highest: a, b, c, d')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Falsy/truthy values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# These are falsy\n",
    "my_list = []\n",
    "my_dict = {}\n",
    "my_set = set()\n",
    "my_tuple = tuple()\n",
    "zero = 0\n",
    "false = False\n",
    "none = None\n",
    "my_str = ''\n",
    "\n",
    "# Basically the rest are truthy\n",
    "# for example:\n",
    "my_second_list = ['foo']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do it like this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if len(my_list) == 0:\n",
    "    print('Empty list is so empty')\n",
    "    \n",
    "if not len(my_dict):\n",
    "    print('Empty dict is also very empty')\n",
    "    \n",
    "if not len(my_set) and not len(my_tuple):\n",
    "    print('Same goes for sets and tuples')\n",
    "    \n",
    "if not bool(zero) and not bool(false) and not bool(none) and len(my_str) == 0:\n",
    "    print('These are also falsy')\n",
    "    \n",
    "if len(my_second_list) > 0:\n",
    "    print('This should be true')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>This is much better!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if not my_list:\n",
    "    print('Empty list is so empty')\n",
    "    \n",
    "if not my_dict:\n",
    "    print('Empty dict is also very empty')\n",
    "    \n",
    "if not my_set and not my_tuple:\n",
    "    print('Same goes for sets and tuples')\n",
    "    \n",
    "if not zero and not false and not none and not my_str:\n",
    "    print('These are also falsy')\n",
    "    \n",
    "if my_second_list:\n",
    "    print('This should be true')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `any` & `all`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "example_collection = ['a', True, 'Python is cool', 123, 0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do it like this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "any_value_truthy = True\n",
    "for val in example_collection:\n",
    "    if val:\n",
    "        any_value_truthy = True\n",
    "        break\n",
    "\n",
    "all_values_truthy = True\n",
    "for val in example_collection:\n",
    "    if not val:\n",
    "        all_values_truthy = False\n",
    "        break\n",
    "        \n",
    "print('any truthy: {}, all truthy: {}'.format(any_value_truthy, all_values_truthy))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>Do it like this!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "any_value_truthy = any(example_collection)\n",
    "all_values_truthy = all(example_collection)\n",
    "print('any truthy: {}, all truthy: {}'.format(any_value_truthy, all_values_truthy))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pythonic substitute for ternary operator\n",
    "Many other programming languages have a ternary operator: `?`. A common use case for the ternary operator is to assign a certain value to a variable based on some condition. In other words, it could be used like this:\n",
    "```\n",
    "variable = some_condition ? some_value : some_other_value\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Instead of doing this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "some_condition = True  # just a dummy condition\n",
    "\n",
    "if some_condition:\n",
    "    variable = 'John'\n",
    "else:\n",
    "    variable = 'Doe'\n",
    "print(variable)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>You can do it like this!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "variable = 'John' if some_condition else 'Doe'\n",
    "print(variable)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Function keywords arguments\n",
    "For better readability and maintainability."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def show_person_details(name, is_gangster, is_hacker, age):\n",
    "    print('name: {}, gangster: {}, hacker: {}, age: {}'.format(\n",
    "        name, is_gangster, is_hacker, age))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>This is not good. It's hard to tell what `True`, `False` and `83` refer here if you are not familiar with the signature of the `show_person_details` function.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show_person_details('John Doe', True, False, 83)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>This is much better!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show_person_details('John Doe', is_gangster=True, is_hacker=False, age=83)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### <font color='green'>Extra: keyword only arguments after `*`</font>\n",
    "This might be useful for example if the signature of the function is likely to change in the future. For example, if there's even a slight chance that one of the arguments may be dropped during the future development, consider using `*`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def func_with_loads_of_args(arg1, *, arg2=None, arg3=None, arg4=None, arg5='boom'):\n",
    "    pass\n",
    "\n",
    "# This won't work because only keyword arguments allowed after *\n",
    "#func_with_loads_of_args('John Doe', 1, 2)\n",
    "\n",
    "# This is ok\n",
    "func_with_loads_of_args('John Doe', arg4='foo', arg5='bar', arg2='foo bar')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Multiple assigment\n",
    "Let's say we want to swap the values of two variables."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do it like this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# original values\n",
    "a = 1\n",
    "b = 2\n",
    "\n",
    "# swap\n",
    "tmp = a\n",
    "a = b\n",
    "b = tmp\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>Do it like this!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# original values\n",
    "a = 1\n",
    "b = 2\n",
    "\n",
    "# swap\n",
    "a, b = b, a\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## (Un)packing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_list = [1, 2, 3, 4, 5, 6]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color='red'>Don't do something like this.</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "first = my_list[0]\n",
    "last = my_list[-1]\n",
    "middle = my_list[1:-1]\n",
    "print(first, middle, last)\n",
    "\n",
    "packed = [first] + middle + [last]\n",
    "assert packed == my_list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <font color='green'>This is the Pythonic way!</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# unpacking\n",
    "first, *middle, last = my_list\n",
    "print(first, middle, last)\n",
    "\n",
    "# packing\n",
    "packed = [first, *middle, last]\n",
    "assert packed == my_list"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
